Ceci est un résumé de notre base de données produit : rangeIndex correspond au nombre de produits disponibles Columns correspondra aux différentes informations qu'on va avoir pour chaque produit, et dType au format de l'information : Ici on aura principalement des informations quantitatives et des informations catégorielles

<class 'pandas.core.frame.DataFrame'>
RangeIndex: 320772 entries, 0 to 320771
Columns: 162 entries, code to water-hardness_100g
dtypes: float64(106), object(56)
memory usage: 396.5+ MB

Dans le contexte de notre étude, nous allons principalement travaillé sur les valeurs nutritionnelles.

Sur cette base de données, j'ai décidé de garder uniquement les informations nutritionnelles dont nous manquons cette information sur plus de 90% de produits. Une exception a été faire pour la valeur fruits-vegetables-nuts_100g qui est une information importante pour le calcul du nutriscore

Ensuite, je vous propose cette matrice de corrélation entre les différentes valeurs restantes

On voit que certaines valeurs nutritionnelles sont corrélées, et donc on pourrait s'imaginer d'en garder qu'un seul. De même, certaines valeurs sont corrélées à 1, ce qui signifie que les deux valeurs se comportent exactement de la même façon. Dans le cadre de notre analyse, on va se concentrer particulièrement sur les données relatives au nutriscore FR. Selon le site : https://quoidansmonassiette.fr/comment-est-calcule-le-nutri-score-logo-nutritionnel/ , le nutriscore est calculé à partir des données suivantes :

  • Energie : 'energy_100g'
  • les acides gras saturés (g/100g) : 'saturated-fat_100g'
  • les sucres simples (g/100g) : 'sugars_100g'
  • le sel (mg/100g) : 'sodium_100g' ou 'salt_100g', mais on prendre le salt car il y a le pourcentage de remplissage de sel > que celui du sodiul
  • les fibres (g/100g) : 'fiber_100g'
  • les protéines (g/100g) : 'proteins_100g'
  • les fruits et légumes : 'fruits-vegetables-nuts_100g'
  • légumineuses et fruits à coque (g/100g) : 'fruits-vegetables-nuts_100g' Donc on réduira le tableau à ces principales données + 'nutrition-score-fr_100g'

Analyse univariée des différentes valeurs.¶

On va commencer par analyser les différentes valeurs que prend chaque valeurs nutritionnelles. Le but de cette exercice est surtout de pouvoir identifier rapidement les valeurs aberrantes qu'on décidera par la suite de supprimer.

energy_100g saturated-fat_100g sugars_100g salt_100g fiber_100g proteins_100g fruits-vegetables-nuts_100g nutrition-score-fr_100g
count 2.611130e+05 229554.000000 244971.000000 255510.000000 200886.000000 259922.000000 3036.000000 221210.000000
mean 1.141915e+03 5.129932 16.003484 2.028624 2.862111 7.075940 31.458587 9.165535
std 6.447154e+03 8.014238 22.327284 128.269454 12.867578 8.409054 31.967918 9.055903
min 0.000000e+00 0.000000 -17.860000 0.000000 -6.700000 -800.000000 0.000000 -15.000000
25% 3.770000e+02 0.000000 1.300000 0.063500 0.000000 0.700000 0.000000 1.000000
50% 1.100000e+03 1.790000 5.710000 0.581660 1.500000 4.760000 23.000000 10.000000
75% 1.674000e+03 7.140000 24.000000 1.374140 3.600000 10.000000 51.000000 16.000000
max 3.251373e+06 550.000000 3520.000000 64312.800000 5380.000000 430.000000 100.000000 40.000000

On remarquera que nous allons avoir des valeurs d'énergie supérieures aux maximum connu dans la littérature (>3700kj), et des valeurs supérieures à 100g pour les différents nutriments sur un échantillon de 100g et on supprimera la ligne qui ont que des valeurs nulles. Cela nous donne un récap de notre dataframe comme le suivant :

energy_100g saturated-fat_100g sugars_100g salt_100g fiber_100g proteins_100g fruits-vegetables-nuts_100g nutrition-score-fr_100g
count 260219.000000 160815.000000 207875.000000 2.211780e+05 132048.000000 206287.000000 2074.000000 221210.000000
mean 1116.159059 7.316862 18.836645 1.833934e+00 4.308964 8.919932 46.050275 9.165535
std 784.412709 8.565257 21.775376 6.673844e+00 5.065973 8.210266 28.703994 9.055903
min 0.000000 0.000100 0.000100 5.000000e-08 0.000100 0.000100 1.000000 -15.000000
25% 372.000000 1.540000 3.200000 1.524000e-01 1.500000 3.330000 20.350000 1.000000
50% 1096.000000 4.500000 9.100000 7.721600e-01 3.000000 6.670000 50.000000 10.000000
75% 1674.000000 10.700000 28.950000 1.524000e+00 5.400000 12.100000 63.000000 16.000000
max 3699.000000 100.000000 100.000000 1.000000e+02 100.000000 100.000000 100.000000 40.000000

Regardons maintenant la répartition des différents produits afin d'y voir des corrélation entre les différents variables

Pour la colonne : energy_100g
Valeur F : 0.04882321605974633
p-value : 0.9999999999999999
Nous pouvons conclure que les scores nutritionnels des différents groupes sont significativement similaires
et le comportement observé entre les groupes n'est probablement pas dû au hasard.

Imputation des valeurs manquantes¶

On imputera les énergies manquantes par la moyenne, car la différence de groupe est non significative

Ensuite, on utilisera la méthode Iterative Imputer pour compléter notre base de données. La méthode IterativeImputer est une technique d'imputation de données manquantes qui utilise un modèle prédictif pour estimer les valeurs manquantes

Ci dessous le tableau descriptif de la base de donnée remplie avec notre technique d'imputation (1er) et le deuxième représente la description de la base de données avant la complétion

energy_100g saturated-fat_100g sugars_100g salt_100g fiber_100g proteins_100g fruits-vegetables-nuts_100g nutrition-score-fr_100g
count 262238.000000 262238.000000 262238.000000 262238.000000 262238.000000 262238.000000 262238.000000 262238.000000
mean 1116.159059 5.081455 16.836399 1.562115 3.978639 8.320228 22.744189 9.183769
std 781.387222 7.858952 21.381024 6.355384 4.370678 7.955714 37.732226 8.931618
min 0.000000 -59.970830 -174.631420 -36.358693 -25.768549 -15.221512 -426.269281 -50.163780
25% 380.000000 0.569588 3.170000 0.124460 1.565434 3.330000 11.019879 2.000000
50% 1105.000000 3.043424 9.000000 0.761762 2.959765 6.394653 29.124140 9.000000
75% 1674.000000 7.140000 25.237468 1.607820 5.133001 11.000000 45.390773 16.000000
max 3699.000000 100.000000 256.458209 100.000000 100.000000 100.000000 394.271543 58.460056
energy_100g saturated-fat_100g sugars_100g salt_100g fiber_100g proteins_100g fruits-vegetables-nuts_100g nutrition-score-fr_100g
count 262238.000000 160815.000000 207875.000000 2.211780e+05 132048.000000 206287.000000 2074.000000 221210.000000
mean 1116.159059 7.316862 18.836645 1.833934e+00 4.308964 8.919932 46.050275 9.165535
std 781.387222 8.565257 21.775376 6.673844e+00 5.065973 8.210266 28.703994 9.055903
min 0.000000 0.000100 0.000100 5.000000e-08 0.000100 0.000100 1.000000 -15.000000
25% 380.000000 1.540000 3.200000 1.524000e-01 1.500000 3.330000 20.350000 1.000000
50% 1105.000000 4.500000 9.100000 7.721600e-01 3.000000 6.670000 50.000000 10.000000
75% 1674.000000 10.700000 28.950000 1.524000e+00 5.400000 12.100000 63.000000 16.000000
max 3699.000000 100.000000 100.000000 1.000000e+02 100.000000 100.000000 100.000000 40.000000

On remarquera que cette méthode n'est clairement pas optimale, puisque des valeurs supérieures à 100 pour les sucres ou 40 pour le nutriscore ont été prédit. Mais en général, on va retrouver les mêmes moyennes globalement. Cela nous aidera uniquement à mieux comprendre .

Analyse en composantes principales (ACP)¶

L'Analyse en Composantes Principales (ACP) est une technique statistique largement utilisée pour transformer des données multidimensionnelles complexes en un ensemble de nouvelles variables, appelées "composantes principales" (F1,F2,F3...), qui capturent l'essentiel de la variabilité des données d'origine. L'objectif principal de l'ACP est de réduire la dimensionnalité des données tout en préservant autant d'informations que possible.

Pour commencer, on va d'abord remettre à l'échelle nos données. Cela permet de centrer les données autour de zéro et de leur donner une variance unitaire.

Notre tableau descriptif de notre base de donnée scalé. On remarquera que la moyenne de toutes les données est à 0 et l'écart type à 1

energy_100g saturated-fat_100g sugars_100g salt_100g fiber_100g proteins_100g fruits-vegetables-nuts_100g nutrition-score-fr_100g
count 262238.00 262238.00 262238.00 262238.00 262238.00 262238.00 262238.00 262238.00
mean 0.00 -0.00 -0.00 -0.00 0.00 0.00 0.00 -0.00
std 1.00 1.00 1.00 1.00 1.00 1.00 1.00 1.00
min -1.43 -8.28 -8.96 -5.97 -6.81 -2.96 -11.90 -6.64
25% -0.94 -0.57 -0.64 -0.23 -0.55 -0.63 -0.31 -0.80
50% -0.01 -0.26 -0.37 -0.13 -0.23 -0.24 0.17 -0.02
75% 0.71 0.26 0.39 0.01 0.26 0.34 0.60 0.76
max 3.31 12.08 11.21 15.49 21.97 11.52 9.85 5.52

On instancie notre ACP et puis on l'entraine avec nos données scalés :

PCA()
In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook.
On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.
PCA()
array([3.43951971e-01, 2.72504153e-01, 1.56389818e-01, 1.11136979e-01,
       6.00696281e-02, 4.77616876e-02, 8.14247195e-03, 4.32921730e-05])

Intéressons nous maintenant à la variance captée par chaque nouvelle composante. La premi!ère composante (F1) capte 34% de la variance de nos données, La 2ème : 27% ... Cela signifie que la première composante explique 34% des informations qu'on a dans notre base de donnée initiale et ainsi de suite

array([ 34.,  62.,  77.,  88.,  94.,  99., 100., 100.])

On a l'habitude en exploration de données de sommer ces variances, car plus on avance dans les composantes, et plus, nous détenons des informations

On voit ici que près de 75% de la variance (ou de l'information de nos données) est comprise dans les 3 premières composantes, et près de 90% dans les 4 premières. On remarque aussi que les 7 premières composantes définissent automatiquement la dernière.

On va à présent voir comment ces nouvelles composantes sont "calculées" à partir de nos valeurs nutritionnelles initiales

F1 F2 F3 F4 F5 F6 F7 F8
energy_100g 0.48 -0.18 0.22 0.19 -0.01 -0.71 0.14 -0.35
saturated-fat_100g 0.47 -0.17 -0.18 0.22 0.61 0.36 0.38 0.14
sugars_100g 0.21 -0.51 0.21 -0.19 -0.61 0.34 0.36 0.03
salt_100g 0.01 0.41 0.43 -0.64 0.24 -0.01 0.41 -0.10
fiber_100g 0.22 0.28 0.62 0.40 -0.04 0.42 -0.34 -0.20
proteins_100g 0.30 0.54 -0.08 0.20 -0.36 -0.16 0.22 0.61
fruits-vegetables-nuts_100g -0.32 -0.36 0.54 0.15 0.25 -0.22 0.01 0.59
nutrition-score-fr_100g 0.51 -0.14 -0.01 -0.50 0.08 -0.02 -0.62 0.30

Alors, comment calcule t-on la première composante F1 ? et bien c'est assez simple : F1 = (0.48 energy_100g) + (0.47 saturated-fat_100g) + ... + (0.51 * nutrition-score-fr_100g)

et F2 ?

F2 = (-0.18 energy_100g) + (-0.17 saturated-fat_100g) + ... + (-0,14* nutrition-score-fr_100g)

Et ainsi de suite

Cette heatmap permet de visualiser aussi très rapidement le poids de chaque valeur sur chaque composante

<Axes: >

Maintenant, essayons de comprendre la corrélation entre ces différentes nouvelles composantes

<Figure size 640x480 with 0 Axes>

Sur les graphes précédents, on pourra étudier la projection des différents produits sur ces nouvelles composantes, un code couleur a été ajouté pour voir comment le code nutriscore se comporte selon les différentes situations et si on arrive à ressortir des clusters. J'ai ausssi ajouté un 3ème graphe qui représente le code couleur telle que c'est actuellment traité pour voir si le clustering est respectée telle que c'est représenté aujourdhui.